
#ifndef _ISO_BAND_UTIL_H_
#define _ISO_BAND_UTIL_H_

#include <vector>
#include <string>
#include <stdexcept>
#include <unordered_map>
#include <emscripten.h>
#include <emscripten/bind.h>

using namespace std;

class IsoBandPoint
{
public:
    IsoBandPoint()
    {
        this->x = 0.0f;
        this->y = 0.0f;
    }
    IsoBandPoint(double x, double y)
    {
        this->x = x;
        this->y = y;
    }
    IsoBandPoint(int x, int y)
    {
        this->x = (double)x;
        this->y = (double)y;
    }
    double x, y;
};

class IsoBandPolygon
{
public:
    std::vector<IsoBandPoint> coords;
    double area = 0.0f;
    std::optional<std::vector<double>> bbox;
};

class IsoBandResult
{
public:
    std::vector<std::vector<IsoBandPolygon>> polygons;
};

// double earthRadius = 63710088e-1;
// double FACTOR = (earthRadius * earthRadius) / 2;
// double PI_OVER_180 = M_PI / 180;
void ringArea(const std::vector<IsoBandPoint> &coords, double &outArea, std::vector<double> &outBbox);
double linear(double a, double b, double v);

double interpolate(double a, double b, double v0, double v1);
double interpolate_a(double a, double b, double minV, double maxV);
double interpolate_b(double a, double b, double minV, double maxV);

const double epsilon = 1.1102230246251565e-16;
const int splitter = 134217729;
const double resulterrbound = (3 + 8 * epsilon) * epsilon;
const double ccwerrboundA = (3 + 16 * epsilon) * epsilon;
const double ccwerrboundB = (2 + 12 * epsilon) * epsilon;
const double ccwerrboundC = (9 + 64 * epsilon) * epsilon * epsilon;

// 向量类型定义
using Vec4 = std::vector<double>;
using Vec8 = std::vector<double>;
using Vec12 = std::vector<double>;
using Vec16 = std::vector<double>;

// 创建指定长度的向量
Vec4 vec4();

Vec8 vec8();

Vec12 vec12();

Vec16 vec16();

// 计算向量元素和
double estimate(int elen, const Vec4 &e);

// 求和函数，处理精度问题
int sum(int elen, const Vec4 &e, int flen, const Vec4 &f, Vec8 &h);

// 自适应高精度叉积计算
double orient2dadapt(double ax, double ay, double bx, double by, double cx, double cy, double detsum);

// 主叉积计算函数
double orient2d(double ax, double ay, double bx, double by, double cx, double cy);

// 判断点是否在多边形内
bool pointInPolygon(const IsoBandPoint &p, const std::vector<IsoBandPolygon> &targetPolygon);

bool isInside(std::vector<IsoBandPoint> &points, const IsoBandPolygon &targetPolygon);

IsoBandPolygon smoothPolygon(const IsoBandPolygon &poly, int iterations);

emscripten::val gen_point(const double &x, const double &y);

emscripten::val gen_typeArray(const std::vector<double> pointCoords);

emscripten::val gen_coords(const std::vector<IsoBandPoint> &bandCoords, bool flipY,
                           double west, double south, double north, double scaleX, double scaleY);

emscripten::val gen_polygon(const std::vector<IsoBandPolygon> &bandRing, bool flipY,
                            double west, double south, double north, double scaleX, double scaleY, int iterations);

#endif